<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
xmlns:v="urn:schemas-microsoft-com:vml">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>Google Maps JavaScript API Example: Marker Drag Events</title>
    <script src="XMLWriter.js" language="javascript"></script>
    <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;sensor=false&amp;key=ABQIAAAAcsQC4UlEfGGG1BcXjw0CLBT4wMoqzwKnkSPeRyykMDy4UjtFyBT6gjGHabu4cgKzjmO6p8h-TYaGVg" type="text/javascript"></script>
    <script src="maps.google.polygon.containsLatLng.js" language="javascript"></script>
    <style type="text/css">
    body{
      	font-family: Arial, sans serif;
  		font-size: 11px;
    }
    #hand {
  		width:31px;
  		height:31px;
  		background-image: url(http://google.com/mapfiles/ms/t/Bsu.png);
	}
	#hand.selected {
  		background-image: url(http://google.com/mapfiles/ms/t/Bsd.png);
	}
	#marker {
  		width:31px;
  		height:31px;
 		background-image: url(http://google.com/mapfiles/ms/t/Bmu.png);
	}
	#marker.selected {
  		background-image: url(http://google.com/mapfiles/ms/t/Bmd.png);
	}
	#polygon {
  		width:31px;
  		height:31px;
  		background-image: url(http://google.com/mapfiles/ms/t/Bpu.png);
	}
	#polygon.selected {
  		background-image: url(http://google.com/mapfiles/ms/t/Bpd.png);
	}
	
    </style>
    
    <script type="text/javascript">

    var prev;
    var markers = [];
    var count = 0;
    var rightClickItem;
    var map;
    var contextmenu;
    var listeners = [];
    var buildings = [];

   // var tmpDoc = document.createDocumentFragment();
    

    markerContextHtml = '<a href="javascript:deleteMarker()"><div class="context">&nbsp;&nbsp;Delete Marker&nbsp;&nbsp;<\/div><\/a>';
    buildingContextHtml = '<a href="javascript:deleteBuilding()"><div class="context">&nbsp;&nbsp;Delete Building&nbsp;&nbsp;<\/div><\/a>';
    function initialize() {
		map = new GMap2(document.getElementById("map_canvas"));
		var center = new GLatLng(43.208366424928606, -77.95392036437988);
		map.setCenter(center, 13);
		map.addControl(new GSmallMapControl());
		map.addControl(new GMapTypeControl());
		map.enableScrollWheelZoom();
	 
	    contextmenu = document.createElement("div");
	    contextmenu.style.visibility="hidden";
	    contextmenu.style.background="#ffffff";
	    contextmenu.style.border="1px solid #8888FF";
	    map.getContainer().appendChild(contextmenu);
	
		select("marker");
		CreateContextMenuListener();
    }

    function CreateMarkerListeners(){
		var listener = GEvent.addListener(map, "click", function(overlay,point) {
			contextmenu.style.visibility = "hidden";
          	if (!overlay) {
				var marker = createMarker(point, count++);
				if(prev){
					var polyline = new GPolyline([
	  					marker.getLatLng(),
	  		           		prev.getLatLng()], 
	                                 	"#ff0000", 2);
					map.addOverlay(polyline);
					marker.points.push(prev);
					prev.points.push(marker);
					marker.lines.push(polyline);
					prev.lines.push(polyline);
				}
				colorCheck(marker);
			}
		});
		listeners.push(listener);
    }

    function CreateContextMenuListener(){
		GEvent.addListener(map,"singlerightclick",function(pixel,tile,overlay) {
			var x = pixel.x;
			var y = pixel.y;
			if (x > map.getSize().width - 120) { x = map.getSize().width - 120 }
			if (y > map.getSize().height - 100) { y = map.getSize().height - 100 }
			var pos = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(x,y));
			if (!overlay){
				contextmenu.style.visibility = "hidden";
			}else{
				if((overlay instanceof GPolygon) ||
					overlay instanceof GMarker && overlay.id != undefined){
					contextmenu.innerHTML = overlay instanceof GPolygon ? buildingContextHtml : markerContextHtml;
					pos.apply(contextmenu);
					contextmenu.style.visibility = "visible";
					rightClickItem = overlay;
				}
			}	
		});       
    }

    function createMarker(point, id){
		var marker = new GMarker(point, {draggable:true});
		marker["id"] = id;
		marker["points"] = [];
		marker["lines"] = [];	
		markers.push(marker);
	        GEvent.addListener(marker, "click", function() {  
			var result;
			if((result = colorCheck(marker)) >= 0){
				toggleLine(marker, result);		
			}
		});
		GEvent.addListener(marker, "dragend", function(){
			redrawLines(marker);
		});	
		map.addOverlay(marker);
		return marker;
    }

    function read(){
		map.clearOverlays();
		markers = [];
		buildings = [];
		prev = undefined;
		var xmlDoc = GXml.parse(document.getElementById("info").value);
		var points = xmlDoc.documentElement.getElementsByTagName("Point");
		var paths = xmlDoc.documentElement.getElementsByTagName("Path");
		var xmlBuildings = xmlDoc.documentElement.getElementsByTagName("Building");
		readPoints(points);
		readPaths(paths);
		readBuildings(xmlBuildings);
    }

    function readPaths(paths){
		var marker = undefined;
		var m2;
		for (var i = 0; i < paths.length; i++){
			var startID = paths[i].getAttribute("startID");
			var endID = paths[i].getAttribute("endID");
			if (marker != undefined && marker.id == startID){
				m2 = markers[findIndex(markers, endID)];
			}else{
				marker = markers[findIndex(markers, startID)];
				m2 = markers[findIndex(markers, endID)];
			}	
			var polyline = new GPolyline([
	  			marker.getLatLng(),
	  		        m2.getLatLng()], 
	                        "#ff0000", 2);	
			map.addOverlay(polyline);
			createLine(marker, m2);
			marker.lines.push(polyline);
			m2.lines.push(polyline);
		}
    }

    function readPoints(points){
		var curCount = 0;
		for (var i = 0; i < points.length; i++) {
			var id = points[i].getAttribute("id");
			var lat = parseFloat(points[i].getAttribute("lat"));
			var lng = parseFloat(points[i].getAttribute("lng"));
			var pt = new GLatLng(lat,lng);
	          	var marker = createMarker(pt, id);
			if(id > curCount);
				curCount = id;
			turnOn(marker);
		}	
		count = ++curCount;
    }

    function readBuildings(xmlBuildings){
        for(var i = 0; i < xmlBuildings.length; i++){
			var name = xmlBuildings[i].getAttribute("Name");
			var desc = xmlBuildings[i].getAttribute("Description");
            var vertices = xmlBuildings[i].getElementsByTagName("Vertex");
            var coords = [];
            for(var j = 0; j < vertices.length; j++){
    			var lat = parseFloat(vertices[j].getAttribute("lat"));
    			var lng = parseFloat(vertices[j].getAttribute("lng"));
    			coords.push(new GLatLng(lat, lng));
            }
            coords.push(coords[0]);
            CreatePolygon(coords, name, desc);
        }
    }

    function deleteMarker(){
		var m = rightClickItem;
		if(m == prev)
			prev = undefined;
		deleteLines(m);
		var i = findIndex(markers, m.id);
		markers.splice(i, 1);
		removeLines(m.lines);
		map.removeOverlay(m);
		contextmenu.style.visibility = "hidden";
    }

	function deleteBuilding(){
		var m = rightClickItem;
		var i = findIndex(buildings, m.id);
		buildings.splice(i, 1);
		map.removeOverlay(m);
		contextmenu.style.visibility = "hidden";
	}
    
    function deleteLines(marker){
		var pts = marker.points;
		for(var i = 0; i < pts.length; i++){
			var j = findIndex(pts[i].points, marker.id);
			pts[i].points.splice(j, 1);
		}
    }
    function toggleLine(marker, id){
		var m2Index;
		if((m2Index = findIndex(marker.points, id)) >= 0){
			removeLine(marker, m2Index);
		}else{
			createLine(marker, markers[findIndex(markers, id)]);
		}
		redrawLines(marker);
    }
    function redrawLines(marker){
		removeLines(marker.lines);
		createLines(marker);
    }
    function createLine(marker, m2){
		marker.points.push(m2);
		m2.points.push(marker);
    }
    function removeLine(marker, m2Index){
		var m2 = marker.points[m2Index];
		marker.points.splice(m2Index,1);
		var m1Index = findIndex(m2.points, marker.id);
		m2.points.splice(m1Index,1);
    }
    function findIndex(pts, id){
	for(var i = 0; i < pts.length; i++){
		if(pts[i].id == id){
			return i;
		}
	}
	return -1;
    }
    function createLines(marker){
	 var pts = marker.points;
         for(var i = 0; i < pts.length; i++){		
			var polyline = new GPolyline([
	  	      		marker.getLatLng(),
	  	      		pts[i].getLatLng()], 
	               		"#ff0000", 2);
			map.addOverlay(polyline);
			marker.lines.push(polyline);
			pts[i].lines.push(polyline);          
         }
    }

    function removeLines(lines){
        while(lines.length != 0){
            map.removeOverlay(lines.pop());
        }
    }

	function colorCheck(marker){
		if(marker == prev){
			toggleColor(marker);
			prev = undefined;
			return -1;
		}else{
			var i = -1;
			if(prev){
				turnOn(prev);
				i = prev.id;
			}
			turnOff(marker);
			prev = marker;
			return i;
		}           
	}
    function toggleColor(marker){
		if(marker.getIcon().image == 'red.png'){
			turnOff(marker);
		}else{
			turnOn(marker);
		}
    }
    function turnOn(marker){
		marker.setImage('red.png');
		marker.getIcon().image = 'red.png';
    }
    function turnOff(marker){
		marker.setImage('blue.png');
		marker.getIcon().image = 'blue.png';       	
    }
    function print(){
		printHeader();
		document.getElementById("info").value += "<Map>\n\n";
		printMarkers();
		printPaths();
		printBuildings();
		document.getElementById("info").value += "</Map>";
    }
    function printHeader(){
		document.getElementById("info").value = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
    }
    function printMarkers(){
		var XML = new XMLWriter();
		XML.BeginNode("Points");
		for(var i = 0; i < markers.length; i++){
			XML.BeginNode("Point");
			XML.Attrib("id", markers[i].id);
			XML.Attrib("lat", markers[i].getLatLng().lat());
			XML.Attrib("lng", markers[i].getLatLng().lng());
			XML.EndNode();
		}
		XML.EndNode();
		document.getElementById("info").value += XML.ToString() + "\n";
    }
    function printPaths(){
		var XML = new XMLWriter();
		XML.BeginNode("Paths");
		for(var i = 0; i < markers.length; i++){
			var marker = markers[i];
			var points = marker.points;
			for(var j = 0; j < points.length; j++){
				if(points[j].id > marker.id){
					XML.BeginNode("Path");
					XML.Attrib("startID", marker.id);
					XML.Attrib("endID", points[j].id);
					XML.EndNode();
				}
			}
		}
		XML.EndNode();
		document.getElementById("info").value += XML.ToString() + "\n";
    }

    function printBuildings(){
    	var XML = new XMLWriter();
    	XML.BeginNode("Buildings");
    	for(var i = 0; i < buildings.length; i++){
    		XML.BeginNode("Building");
    		XML.Attrib("Name", buildings[i].name);
    		XML.Attrib("Description", buildings[i].desc);
    		printBuildingVertices(XML, i);
    		printEntrances(XML, buildings[i]);
    		XML.EndNode();
    	}
    	XML.EndNode();
    	document.getElementById("info").value += XML.ToString() + "\n";
    }

	function printEntrances(XML, building){
		for(var i = 0; i < markers.length; i++){
			if(building.containsLatLng(markers[i].getLatLng())){
				XML.BeginNode("Entrance");
				XML.Attrib("id", markers[i].id);
				XML.EndNode();
			}
		}
	}
    
    function printBuildingVertices(XML, i){
        var vertices = buildings[i].getVertexCount();
		for(var j = 0; j < vertices - 1; j++){
			XML.BeginNode("Vertex");
			XML.Attrib("lat", buildings[i].getVertex(j).lat());
			XML.Attrib("lng", buildings[i].getVertex(j).lng());
			XML.EndNode();
		}     
    }

    function select(action)
    {
        switchState(action);
        clearListeners();
        addListeners(action);
    }

    function switchState(action){
		document.getElementById("hand").className="unselected";
		document.getElementById("polygon").className="unselected";
  		document.getElementById("marker").className="unselected";
  		document.getElementById(action).className="selected";
    }

    function clearListeners(){
        for(var i = 0; i < listeners.length; i++){
        	GEvent.removeListener(listeners[i]);
        }
    }

	function addListeners(action){
		if(action == "marker")
			CreateMarkerListeners();
		if(action == "polygon")
			CreatePolygonListeners();
	}

	function CreatePolygon(vertices, name, desc){
		var polygon = new GPolygon(vertices, "#f33f00", 5, 1, "#ff0000", 0.2);
		map.addOverlay(polygon); 
		polygon.enableEditing({maxVertices: "4"});
		polygon["id"] = buildings.length-1 < 0 ? 0 : buildings[buildings.length-1].id + 1;
		polygon["name"] = name;
		polygon["desc"] = desc;
		buildings.push(polygon); 
		AddPolygonContextMenu(polygon);
	}

	function AddPolygonContextMenu(polygon){     
		GEvent.addListener(polygon, 'click', function(point) {
			contextmenu.style.visibility = "hidden";
			var html = "<form>Building name:<br /> <input type=\"text\" id=\"name\" value=\"" + polygon["name"] + "\"/><br /></form>"
				+ "Building description:<br /> <textarea cols=\"20\" rows=\"4\" id=\"desc\">" + polygon["desc"] + "</textarea>";
		    if (point) {
		        map.openInfoWindow(point, html);
		      } else {
		         map.openInfoWindow(polygon.getBounds().getCenter(), html);  // open info window at the center of polygon
		      }
		      var listener = GEvent.addListener(map, 'infowindowbeforeclose', function(){
		            polygon["name"] = document.getElementById("name").value;
		            polygon["desc"] = document.getElementById("desc").value;
		      });
			  GEvent.addListener(map, 'infowindowclose', function(){
			    	GEvent.removeListener(listener);
			  });
		});	
	}
	
	function CreatePolygonListeners(){
		var listener = GEvent.addListener(map, 'click', function(overlay, latlng) {
			contextmenu.style.visibility = "hidden";
			if (!overlay) {
			   var lat = latlng.lat();
			   var lon = latlng.lng();
			   var latOffset = 0.0001;
			   var lonOffset = 0.0001;
			   var vertices = [
			   		new GLatLng(lat - latOffset, lon + lonOffset),    
			   		new GLatLng(lat + latOffset, lon + lonOffset),     
			   		new GLatLng(lat + latOffset, lon - lonOffset),     
			   		new GLatLng(lat - latOffset, lon - lonOffset),     
			   		new GLatLng(lat - latOffset, lon + lonOffset)   
    			];
			   CreatePolygon(vertices, "", "");		   	
			}
		});
		listeners.push(listener);
	}
    
    </script>
  </head>
 
  <body onload="initialize()" onunload="GUnload()">
  
  <table><tr>
	<td><div id="hand" onclick="select('hand')"/></td>
	<td><div id="marker" onclick="select('marker')"/></td>
	<td><div id="polygon" onclick="select('polygon')"/></td>
  </tr></table>
  
    <div id="map_canvas" style="width: 600px; height: 400px"></div>
    <FORM NAME="testform">
        <INPUT TYPE="button" NAME="btnPrint" Value="Output XML" onClick="print()">
	<INPUT TYPE="button" NAME="btnRead" Value="Read XML" onClick="read()">
    </FORM>
    <textarea rows="30" cols="100" id="info"></textarea>
  </body>
</html>